import { h, render } from 'vue';
import type { Plugin, App } from 'vue';

class DzModalResult {
  type: 'ok' | 'cancel' | 'close' | 'string' = 'ok';
  body?: any = undefined;
}

class DzModalService {
  private _map = new Map();
  private _app?: App = undefined;
  constructor(app: App) {
    if (!app) {
      console.log('DzModal Service constructor error, no app!');
    }
    this._app = app;
  }

  /**
   * 通过url判断一个组件是否打开
   * @param vueUri vue相对于DzModalService的路径
   * @returns boolean 是不是打开了
   */
  public isOpen(vueUri: string) {
    return this._map.has(vueUri);
  }

  public close(vueUri: string, data?: any) {
    const vm = this._map.get(vueUri);
    if (!vm) {
      return;
    }
    vm.props.onClose(data);
    this._map.delete(vueUri);
  }

  public closeAll() {
    this._map.forEach(value => {
      value.props.onClose();
    });
    this._map.clear();
  }

  public openComponent(modal: any, key: string, props?: any): Promise<DzModalResult> {
    return new Promise((reslove, reject) => {
      if (!this._app) {
        reject('_app is undefined');
        return;
      }

      if (this._map.has(key)) {
        if (props && props.closeIfExist) {
          this.close(key);
          reslove(this._ret_ok());
        } else {
          reject(key + ' is showing');
        }
        return;
      }

      const container = document.createElement('div');
      document.body.appendChild(container);

      // 这里需要合并props，传入到组件modal
      const vm = h(modal, {
        ...props,
        onOk: (data?: any) => {
          // 弹出框关闭时移除节点
          render(null, container);
          document.body.removeChild(container);
          this._map.delete(key);
          reslove(this._ret_ok(data));
        },
        onCancel: (data?: any) => {
          // 弹出框关闭时移除节点
          render(null, container);
          document.body.removeChild(container);
          this._map.delete(key);
          reslove(this._ret_cancel(data));
        },
        onClose: (data?: any) => {
          // 弹出框关闭时移除节点
          render(null, container);
          document.body.removeChild(container);
          this._map.delete(key);
          reslove(this._ret_close(data));
        }
      });
      // 这里很重要，关联app上下文
      vm.appContext = this._app._context;
      render(vm, container);
      this._map.set(key, vm);
    });
  }

  public _ret_ok(data?: any): DzModalResult {
    const result = new DzModalResult();
    result.type = 'ok';
    result.body = data;
    return result;
  }

  public _ret_cancel(data?: any): DzModalResult {
    const result = new DzModalResult();
    result.type = 'cancel';
    result.body = data;
    return result;
  }

  public _ret_close(data?: any): DzModalResult {
    const result = new DzModalResult();
    result.type = 'close';
    result.body = data;
    return result;
  }
}

let g_dzModal: any = undefined;
const plugin: Plugin = {
  install(app: App) {
    console.log('dzModalService install');
    g_dzModal = new DzModalService(app);
  }
};

/**
 * 打开一个vue3组件
 * @param {Object} modal vue3组件,一般通过
 * @param {String} key 唯一标识符
 * @param {Object} props 组件的属性
 * @returns
 */
export function openComponent(
  modal: any,
  key: string,
  props: { closeIfExist?: boolean; [key: string]: any } = { closeIfExist: false }
) {
  return g_dzModal.openComponent(modal, key, props);
}

/**
 * 判断指定的组件是否已打开
 * @param {String} key
 * @returns {Boolean} 组件是否已打开
 */
export function componentIsOpen(key: string): boolean {
  return g_dzModal.isOpen(key);
}

/**
 * 关闭指定的组件
 * @param {String} key - 要关闭的组件的唯一标识符
 * @param {Object} data - 关闭组件时传入的数据
 * @returns 关闭操作的返回结果
 */
export function closeComponent(key: string, data?: any) {
  return g_dzModal.close(key, data);
}

/**
 * 关闭所有模态框组件
 */
export function clearComponent() {
  return g_dzModal.closeAll();
}

export default plugin;
